package Thread;



import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;

/****
 * 并发包队列
 * 在并发队列上JDK提供了两套实现，
 * 一个是以ConcurrentLinkedQueue为代表的高性能队列，
 * 一个是以BlockingQueue接口为代表的阻塞队列，无论哪种都继承自Queue。
 * 队列遵循的原则  先进先出 后进后出
 * 队列分为 阻塞队列及非阻塞队列
 * 区别在于：阻塞队列 队列满时，就会进入到阻塞，当队列为空，消费者也会等待(阻塞)
 *         非阻塞队列在于有界和无界
 * **/


/***
 * 1.ConcurrentLinkedQueue
 * 是一个基于链接节点的无界线程安全队列。该队列的元素遵循先进先出的原则。头是最先
 * 加入的，尾是最近加入的，该队列不允许null元素。
 * 重要方法:
 * add 和offer() 都是加入元素的方法(在ConcurrentLinkedQueue中这俩个方法没有任何区别)
 * poll() 和 peek() 都是取头元素节点，但是前者会删除元素，后者不会。
 * ***/


/***
 *都是线程安全的，可以去看一下源码，都用了lock锁
 * */

/***
 * 2.阻塞队列（BlockingQueue）
 * 是一个支持两个附加操作的队列。这两个附加的操作是：
 * 在队列为空时，获取元素的线程会等待队列变为非空。
 * 当队列满时，存储元素的线程会等待队列可用。
 * 阻塞队列常用于生产者和消费者的场景，
 * 生产者是往队列里添加元素的线程，
 * 消费者是从队列里拿元素的线程。
 * 阻塞队列就是生产者存放元素的容器，而消费者也只从容器里拿元素。
 * ***/
public class ThreadQueue {

   public static void main(String[] args) throws Exception {
        ConcurrentLinkedQueue concurrentLinkedQueue = new ConcurrentLinkedQueue();//无界，不需要初始化长度
       concurrentLinkedQueue.add("libofei");  //add方法和offer方法相同
       concurrentLinkedQueue.add("guohao");
       System.out.println(concurrentLinkedQueue.size()); //打印长度
       System.out.println(concurrentLinkedQueue.poll()); //poll方法消费后会删除
       System.out.println(concurrentLinkedQueue.peek()); //peek方法消费后不会删除，还是之前的长度
       System.out.println(concurrentLinkedQueue.size()); //打印消费后长度


       /***
        * 有界队列
        * LinkedBlockingQueue
        * LinkedBlockingQueue阻塞队列大小的配置是可选的，
        * 如果我们初始化时指定一个大小，它就是有边界的，如果不指定，它就是无边界的。
        * 说是无边界，其实是采用了默认大小为Integer.MAX_VALUE的容量 。它的内部实现是一个链表。
        *
        * ArrayBlockingQueue是一个有边界的阻塞队列，
        * 它的内部实现是一个数组。有边界的意思是它的容量是有限的，
        * 我们必须在其初始化的时候指定它的容量大小，容量大小一旦指定就不可改变。
        * ArrayBlockingQueue是以先进先出的方式存储数据，
        *
        * SynchronousQueue队列内部仅允许容纳一个元素
        * 。当一个线程插入一个元素后会被阻塞，除非这个元素被另一个线程消费
        * **
        */

       //初始化时需要赋给长度，队列满时会发生阻塞
       ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3);
       arrayBlockingQueue.offer("li");
       arrayBlockingQueue.offer("bo");
       arrayBlockingQueue.offer("fei");

       // 添加阻塞队列(设置超时时间2秒)
       Boolean success = arrayBlockingQueue.offer("张三", 1, TimeUnit.SECONDS);
       System.out.println(success);  //是否添加成功

        System.out.println(arrayBlockingQueue.size());
        System.out.println(arrayBlockingQueue.poll());

       Boolean isSuccess = arrayBlockingQueue.offer("张三", 1, TimeUnit.SECONDS);
       System.out.println(isSuccess);  //是否添加成功
       System.out.println(arrayBlockingQueue.poll());
       System.out.println(arrayBlockingQueue.poll());
       System.out.println(arrayBlockingQueue.poll());
       System.out.println(arrayBlockingQueue.size());
   }
}
